﻿using Behaving;
using Behaving.Composites;
using FluentAssertions;
using NUnit.Framework;

namespace Behaving.Tests.CompositeTests
{
    [TestFixture]
    public class UtilitySelectorTests
    {
        [Test]
        public void When_no_utility_is_above_zero_then_then_no_behaviour_is_run()
        {
            BehaviourUtility b1;
            BehaviourUtility b2;
            BehaviourUtility b3;
            BehaviourTree behaviourTree =
                new BehaviourTree(
                    new UtilitySelector(
                        b1 = new BehaviourUtility(b => -1, new ExecutionCounter(RunningState.Failure)),
                        b2 = new BehaviourUtility(b => -2, new ExecutionCounter(RunningState.Failure)),
                        b3 = new BehaviourUtility(b => -3, new ExecutionCounter(RunningState.Failure))));

            behaviourTree.Tick().Should().Be(RunningState.Failure);
            Assertions.AssertWasNotCalled((ExecutionCounter)b1.Behaviour);
            Assertions.AssertWasNotCalled((ExecutionCounter)b2.Behaviour);
            Assertions.AssertWasNotCalled((ExecutionCounter)b3.Behaviour);
        }

        [Test]
        public void The_best_utility_behaviour_is_run()
        {
            BehaviourUtility b1;
            BehaviourUtility behaviourUtilityToRun;
            BehaviourUtility b3;
            BehaviourTree behaviourTree =
                  new BehaviourTree(
                      new UtilitySelector(
                          b1 = new BehaviourUtility(b => -1, new ExecutionCounter(RunningState.Failure)),
                          behaviourUtilityToRun = new BehaviourUtility(b => 1, new ExecutionCounter(RunningState.Running)),
                          b3 = new BehaviourUtility(b => -3, new ExecutionCounter(RunningState.Failure))));

            behaviourTree.Tick().Should().Be(RunningState.Running);
            Assertions.AssertWasNotCalled((ExecutionCounter)b1.Behaviour);
            Assertions.AssertWasStartedAndExecuted((ExecutionCounter)behaviourUtilityToRun.Behaviour);
            Assertions.AssertWasNotCalled((ExecutionCounter)b3.Behaviour);
        }

        [Test]
        public void A_new_best_utility_behaviour_is_run()
        {
            BehaviourUtility b1;
            BehaviourUtility behaviourUtilityToRunFirst;
            BehaviourUtility behaviourUtilityToRunSecond;
            BehaviourTree behaviourTree =
                  new BehaviourTree(
                      new UtilitySelector(
                          b1 = new BehaviourUtility(b => -1, new ExecutionCounter(RunningState.Failure)),
                          behaviourUtilityToRunFirst = new BehaviourUtility(b => 1, new ExecutionCounter(RunningState.Running)),
                          behaviourUtilityToRunSecond = new BehaviourUtility(b => -3, new ExecutionCounter(RunningState.Running))));

            behaviourTree.Tick().Should().Be(RunningState.Running);
            Assertions.AssertWasNotCalled((ExecutionCounter)b1.Behaviour);
            Assertions.AssertWasStartedAndExecuted((ExecutionCounter)behaviourUtilityToRunFirst.Behaviour);
            Assertions.AssertWasNotCalled((ExecutionCounter)behaviourUtilityToRunSecond.Behaviour);

            behaviourUtilityToRunFirst.UtilityFunction = b => -1;
            behaviourUtilityToRunSecond.UtilityFunction = b => 1;

            behaviourTree.Tick().Should().Be(RunningState.Running);
            Assertions.AssertWasNotCalled((ExecutionCounter)b1.Behaviour);
            Assertions.AssertWasStopped((ExecutionCounter)behaviourUtilityToRunFirst.Behaviour);
            Assertions.AssertWasStartedAndExecuted((ExecutionCounter)behaviourUtilityToRunSecond.Behaviour);
        }
    }
}